﻿/*
 * This software is the confidential and proprietary
 * information of NetBay
 * Such confidential information should not be disclosed
 * NetBay copyright(c) 2010
 */

#region Using
using System;
using System.Collections.Generic;
using NetBay.Core.Log;
using System.IO;
using System.Security.AccessControl;
using NetBay.Core.BusinessEntities;
using System.Diagnostics;
using System.Security.Principal;
#endregion

namespace NetBay.Core.Tools
{
    /// <summary>
    /// 
    /// </summary>
    public static class FileTools
    {
        /// <summary>
        /// Creates the file.
        /// </summary>
        /// <param name="p_sFileName">Name of the file.</param>
        /// <param name="p_bCreateDirectory">if set to <c>true</c> [create directory].</param>
        /// <returns></returns>
        public static bool CreateFile(string p_sFileName, bool p_bCreateDirectory)
        {
            try
            {
                FileInfo L_oFile = new FileInfo(p_sFileName);
                if (p_bCreateDirectory)
                {
                    if (!Directory.Exists(L_oFile.Directory.FullName))
                    {
                        FileTools.CreateDirectory(L_oFile.Directory.FullName);
                    }
                }
                if (!File.Exists(p_sFileName))
                {
                    FileStream stream = L_oFile.Create();
                    stream.Close();
                }
            }
            catch (IOException ex)
            {
                LogManager.Instance().LogErrorFormat(
                    ex,
                    "Failed to create file: {0}", p_sFileName);
                return false;
            }
            return true;
        }

        /// <summary>
        /// Check access to parent directory and creates the given directory.
        /// </summary>
        public static bool CreateDirectory(string p_sDirectoryPath)
        {
            if (Directory.Exists(p_sDirectoryPath))
            {
                return true;
            }
            else
            {
                DirectoryInfo parentDir = Directory.GetParent(p_sDirectoryPath);
                while (!parentDir.Exists)
                {
                    parentDir = Directory.GetParent(parentDir.FullName);
                }
                if (CheckDirectoryAccessRights(parentDir.FullName, FileSystemRights.CreateDirectories).IsValid)
                {
                    Directory.CreateDirectory(p_sDirectoryPath);
                    LogManager.Instance().LogDebugFormat("Create directory '{0}' done",
                        p_sDirectoryPath);
                    return true;
                }
                else
                {
                    LogManager.Instance().LogErrorFormat("Unable to create parent directory {0} for {1}",
                        parentDir.FullName,
                        p_sDirectoryPath);
                    return false;
                }
            }
        }

        /// <summary>
        /// Checks the directory access rights.
        /// </summary>
        /// <param name="p_sFilePath">The file path.</param>
        /// <returns></returns>
        public static ReturnObject CheckDirectoryAccessRights(string p_sFilePath, params FileSystemRights[] p_oRights)
        {
            ReturnObject returnObject = new ReturnObject();
            if (Directory.Exists(p_sFilePath))
            {
                DirectorySecurity dSecurity = Directory.GetAccessControl(p_sFilePath);
                AuthorizationRuleCollection rules = dSecurity.GetAccessRules(true, true, typeof(SecurityIdentifier));

                return CheckRights(p_oRights, rules);
            }
            return returnObject;
        }

        /// <summary>
        /// Checks the file access rights.
        /// </summary>
        /// <param name="p_sFilePath">The file path.</param>
        /// <param name="p_oRights">The rights.</param>
        /// <returns></returns>
        public static ReturnObject CheckFileAccessRights(string p_sFilePath, params FileSystemRights[] p_oRights)
        {
            ReturnObject returnObject = new ReturnObject();
            if (File.Exists(p_sFilePath))
            {
                FileSecurity fSecurity = File.GetAccessControl(p_sFilePath);
                AuthorizationRuleCollection rules = fSecurity.GetAccessRules(true, true, typeof(SecurityIdentifier));

                return CheckRights(p_oRights, rules);
            }
            returnObject.IsValid = false;
            return returnObject;
        }

        /// <summary>
        /// Checks the rules contains given rights.
        /// </summary>
        /// <param name="p_oRights">The rights.</param>
        /// <param name="p_oRules">The rules.</param>
        /// <returns></returns>
        private static ReturnObject CheckRights(FileSystemRights[] p_oRights, AuthorizationRuleCollection p_oRules)
        {
            bool contains = false;
            ReturnObject returnObject = new ReturnObject();
            foreach (FileSystemRights right in p_oRights)
            {
                foreach (FileSystemAccessRule rule in p_oRules)
                {
                    if (((int)right & (int)rule.FileSystemRights) == (int)right)
                    {
                        contains = true;
                        break;
                    }
                }

                returnObject.IsValid = returnObject.IsValid && contains;
                contains = false;
            }

            if (!returnObject.IsValid)
            {
                returnObject.ErrorMessage = "FileAccessError";
            }
            return returnObject;
        }

        public static bool CopyFilesFromDirectory(
            string p_sSrcDirectoryPath,
            string p_sDestDirectoryPath,
            List<string> p_oValidFileExtensionList,
            bool p_bCopySubDirectory)
        {
            bool valid = false;
            DirectoryInfo dir = new DirectoryInfo(p_sSrcDirectoryPath);
            if (dir.Exists)
            {
                List<FileInfo> files = new List<FileInfo>(dir.GetFiles());
                if (p_oValidFileExtensionList != null && p_oValidFileExtensionList.Count > 0)
                {
                    files = GetFilterFileInfoList(
                        files,
                        p_oValidFileExtensionList);
                }
                if (!Directory.Exists(p_sDestDirectoryPath))
                {
                    CreateDirectory(p_sDestDirectoryPath);
                }
                foreach (FileInfo file in files)
                {
                    string newFilePath = Path.Combine(
                        p_sDestDirectoryPath,
                        Path.GetFileName(file.FullName));

                    file.CopyTo(newFilePath, true);
                }
                valid = true;
                if (p_bCopySubDirectory)
                {
                    DirectoryInfo[] directories = dir.GetDirectories();
                    foreach (DirectoryInfo directory in directories)
                    {
                        string newDestPath =
                            Path.Combine(
                                p_sDestDirectoryPath,
                                directory.Name);
                        valid = valid && CopyFilesFromDirectory(
                            directory.FullName,
                            newDestPath,
                            p_oValidFileExtensionList,
                            true);
                    }
                }

                LogManager.Instance().LogDebugFormat(
                    "Copy file from '{0}' to '{1}' done (recursive={2})",
                    p_sSrcDirectoryPath,
                    p_sDestDirectoryPath,
                    p_bCopySubDirectory);
                return valid;
            }
            return valid;
        }

        /// <summary>
        /// Gets the filter file info list.
        /// </summary>
        /// <param name="p_oFileList">The file list.</param>
        /// <param name="p_oFileExtensions">The file extensions.</param>
        /// <returns></returns>
        public static List<FileInfo> GetFilterFileInfoList(
            List<FileInfo> p_oFileList,
            List<string> p_oFileExtensions)
        {
            p_oFileList = p_oFileList.FindAll(
                delegate(FileInfo f)
                {
                    foreach (string extension in p_oFileExtensions)
                    {
                        string newExtension = extension;
                        if (newExtension.StartsWith("."))
                        {
                            newExtension = String.Concat(".", extension);
                        }
                        if (newExtension.ToLower().Equals(f.Extension.ToLower()))
                        {
                            return true;
                        }
                    }
                    return false;
                });
            return p_oFileList;
        }

        /// <summary>
        /// Registers the DLL with a regasm.
        /// </summary>
        /// <param name="p_sDllPath">The DLL path.</param>
        public static bool RegisterDll(string p_sDllPath)
        {
            if (File.Exists(p_sDllPath))
            {
                ProcessStartInfo startInfo = new ProcessStartInfo(
                    @"C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\regasm.exe");
                startInfo.WorkingDirectory = Path.GetDirectoryName(p_sDllPath);
                startInfo.Arguments = string.Format("{0} /codebase /tlb:{1}.tlb",
                        Path.GetFileName(p_sDllPath),
                        Path.GetFileNameWithoutExtension(p_sDllPath));

                Process process = Process.Start(startInfo);
                process.WaitForExit();
                if (process.ExitCode == 0)
                {
                    LogManager.Instance().LogDebugFormat(
                        "Register dll DONE (dllPath={0})",
                        p_sDllPath);
                }
                return process.ExitCode == 0;
            }
            else
            {
                return false;
            }
        }
    }
}
